package com.tbit.uqbike.protocol.AnalyzeImpl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tbit.uqbike.protocol.ABaseHandleObj;
import com.tbit.uqbike.protocol.ATerPkg;
import com.tbit.uqbike.tergateway.data.TerGatewayData;
import com.tbit.uqbike.tergateway.entity.AConnInfo;
import com.tbit.uqbike.tergateway.entity.RemoteControl;
import com.tbit.uqbike.tergateway.mtpkg.*;
import com.tbit.uqbike.tergateway.wa205pkg.CommRsp;
import com.tbit.uqbike.util.AesUtil;
import com.tbit.uqbike.util.CharsetName;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by MyWin on 2018/5/16 0016.
 */
public class MeituanDeEnCoder extends AProtocol {
    private static Logger logger = LoggerFactory.getLogger(MeituanDeEnCoder.class);
    public static final String protocolName = "MTTer";

    public static final String KEY = "wIrynK2rzGMxRZh+";

    public static final int LEN_PKG_HEAD = 26;
    public static final int LEN_PAYLOAD_MAX = 10240;

    public static final int INDEX_LEN = 22;

    static {
    }

    public static class BaseJsonPkg {
        public String id;
        public String data;
    }

    @Override
    public List<ATerPkg> analyzeTerPkg(AConnInfo conn, ByteBuf in) {
        List<ATerPkg> list = new LinkedList<>();
        int pkgLen;
        while (in.readableBytes() >= LEN_PKG_HEAD) {
            // 直接取长度字段
            int len = in.getIntLE(INDEX_LEN);
            if (len > LEN_PAYLOAD_MAX || len <= 0) {
                // 直接断链
                conn.closeConn();
                return list;
            }
            if (in.readableBytes() >= LEN_PKG_HEAD + len) {
                byte[] allPkg = new byte[LEN_PKG_HEAD + len];
                in.getBytes(0, allPkg);
                MtPkgHead head = new MtPkgHead();
                head.type = in.readUnsignedByte();
                head.version = in.readUnsignedByte();
                byte[] mnoBs = new byte[16];
                in.readBytes(mnoBs);
                try {
                    head.sn = new String(mnoBs, 0, mnoBs.length, CharsetName.US_ASCII);
                } catch (UnsupportedEncodingException e) {
                    conn.closeConn();
                    return list;
                }
                head.crc = in.readIntLE();
                head.len = in.readIntLE();
                byte[] payloadBs = new byte[len];
                in.readBytes(payloadBs);
                try {
                    String jsonStr = new String(payloadBs, 0, payloadBs.length, CharsetName.UTF_8);
                    logger.info(String.format("type:%d,jsonStr:%s", head.type, jsonStr));
                    BaseJsonPkg jsonPkg;
                    if (head.type == 0x50) {
                        jsonPkg = new BaseJsonPkg();
                        jsonPkg.id = "";
                        jsonPkg.data = jsonStr;
                    } else {
                        jsonPkg = JSONObject.parseObject(jsonStr, BaseJsonPkg.class);
                    }
                    if (null == jsonPkg || null == jsonPkg.id || null == jsonPkg.data) {
                        conn.closeConn();
                        return list;
                    }
                    ATerPkg pkg = analyzePkg(head, jsonPkg);
                    if (null != pkg) {
                        pkg.signPkg = allPkg;
                        pkg.setConnId(conn.connId);
                        pkg.setProName(getProtocolName());
                        if (pkg.autoRsp()) {
                            ByteBuf rsp = pkg.getRsp(conn, AAutoProtocol.getProtocol(protocolName));
                            if (null != rsp && rsp.readableBytes() > 0) {
                                conn.downMsg(rsp);
                            }
                        }
                        list.add(pkg);
                    }
                } catch (UnsupportedEncodingException e) {
                    conn.closeConn();
                    return list;
                }
            } else {
                return list;
            }
        }
        return list;
    }

    /**
     * pkg(head,payload)
     * payload(id,data)
     * data >(base64)> bytes
     * bytes >(aes128)> bytes
     * bytes >(utf-8)> string
     * string >json> object
     *
     * @param head
     * @param jsonPkg
     * @return
     */
    private ATerPkg analyzePkg(MtPkgHead head, BaseJsonPkg jsonPkg) {
        MtBasePkg pkg = null;
        // 先解析jsonPkg
        try {
            String decryptData;
            if (head.type == 0x50) {
                decryptData = jsonPkg.data;
            } else {
                decryptData = AesUtil.Decrypt(jsonPkg.data, KEY);
            }
            // 直接打印日志
            logger.info(String.format("type:%d,id:%s,data:%s", head.type, jsonPkg.id, decryptData));
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            switch (head.type) {
                case 0x50:
                    pkg = mapper.readValue(decryptData, MtLogin.class);
                    break;
                case 0x53:
                    pkg = mapper.readValue(decryptData, MtHeart.class);
                    break;
                case 0x55:
                    pkg = mapper.readValue(decryptData, MtControl.class);
                    break;
                case 0x56:
                    MtInfoUpload temp = mapper.readValue(decryptData, MtInfoUpload.class);
                    if (temp.type == 1) {
                        temp.batteryInfo = mapper.readValue(decryptData, MtInfoUpload.BatteryInfo.class);
                    } else if (temp.type == 2) {
                        temp.gpsInfo = mapper.readValue(decryptData, MtInfoUpload.GpsInfo.class);
                    } else if (temp.type == 3) {
                        temp.carInfo = mapper.readValue(decryptData, MtInfoUpload.CarInfo.class);
                    } else {
                        return null;
                    }
                    pkg = temp;
                    break;
                case 0x57:
                    pkg = mapper.readValue(decryptData, MtAlarmUp.class);
                    break;
                case 0x58:
                    pkg = mapper.readValue(decryptData, MtEventUpload.class);
                    break;
                default:
                    break;
            }
            if (pkg != null) {
                pkg.head = head;
                pkg.mno = head.sn;
                pkg.serNo = jsonPkg.id;
                return pkg;
            }
        } catch (Exception e) {
            logger.error("analyzePkg", e);
        }
        return null;
    }

    public ByteBuf buildDownMsg(MtPkgHead head) {
        ByteBuf byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
        byteBuf.writeByte(head.type);
        byteBuf.writeByte(head.version);
        byte[] bs;
        try {
            bs = head.sn.getBytes(CharsetName.US_ASCII);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
        byteBuf.writeBytes(bs);
        byteBuf.writeIntLE(head.crc);
        byteBuf.writeIntLE(0);
        return byteBuf;
    }

    public ByteBuf buildDownMsg(MtPkgHead head, String id, String jsonStr) {
        ByteBuf byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
        byteBuf.writeByte(head.type);
        byteBuf.writeByte(head.version);
        byte[] bs;
        try {
            bs = head.sn.getBytes(CharsetName.US_ASCII);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
        byteBuf.writeBytes(bs);
        byteBuf.writeIntLE(head.crc);
        // 根据jsonStr计算长度
        try {
            BaseJsonPkg pkg = new BaseJsonPkg();
            pkg.id = id;
            pkg.data = jsonStr;
            bs = JSONObject.toJSONString(pkg).getBytes(CharsetName.UTF_8);
            head.len = bs.length;
            byteBuf.writeIntLE(head.len);
            byteBuf.writeBytes(bs);
            return byteBuf;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public MtPkgHead getDefHead(int type, String sn) {
        MtPkgHead head = new MtPkgHead();
        head.type = type;
        head.sn = sn;
        return head;
    }

    @Override
    public ByteBuf builtRemoteControlPkg(AConnInfo conn, ABaseHandleObj aBaseHandleObj) {
        ByteBuf byteBuf = null;
        RemoteControl remoteControl = (RemoteControl) aBaseHandleObj;
        try {
            TerControl terControl = TerControl.buildTerControl(remoteControl);
            if (null != terControl) {
                String data = JSONObject.toJSONString(terControl);
                byteBuf = buildDownMsg(getDefHead(0x55, remoteControl.sn), "", data);
            }
            // 创建完成 写入全局缓存
            if (null != byteBuf) {
                TerGatewayData.setStrSerNoMap(remoteControl.serNO, remoteControl);
                return byteBuf;
            }
        } catch (Exception e) {
            if (byteBuf != null) {
                byteBuf.clear();
            }
            logger.error("构造下行数据包异常", e);
        }
        return null;
    }

    @Override
    public String getProtocolName() {
        return protocolName;
    }

    public static void writeDownBytes(ByteBuf byteBuf, Object obj) {
        String str = JSON.toJSONString(obj);
        try {
            byte[] bs = str.getBytes(CharsetName.US_ASCII);
            byteBuf.writeShort(bs.length);
            byteBuf.writeBytes(bs);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public static void getCommRsp(ByteBuf byteBuf, String result) {
        CommRsp rsp = new CommRsp();
        rsp.result = result;
        writeDownBytes(byteBuf, rsp);
    }
}
